//SPDX-FileCopyrightText: Copyright 2025-2025 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package board_dao

import (
	"context"

	"gitcode.com/eteam/api-server/dao/common"
	"gitcode.com/eteam/proto-gen-go.git/board_draw_api"
	"gitcode.com/eteam/proto-gen-go.git/board_draw_type"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/mongo"
	"go.mongodb.org/mongo-driver/mongo/options"
	"google.golang.org/protobuf/proto"
	"google.golang.org/protobuf/types/known/anypb"
)

type NodeStyleInfoDbItem struct {
	BgColor     string `bson:"bgColor"`
	BorderWidth string `bson:"borderWidth"`
	BorderColor string `bson:"borderColor"`
	FontColor   string `bson:"fontColor"`
	Layer       uint32 `bson:"layer"`
}

type DrawNodeInfoDbItem struct {
	NodeId      string              `bson:"_id"`
	BoardId     string              `bson:"boardId"`
	DrawId      string              `bson:"drawId"`
	NodeStyle   NodeStyleInfoDbItem `bson:"nodeStyle"`
	X           float32             `bson:"x"`
	Y           float32             `bson:"y"`
	W           float32             `bson:"w"`
	H           float32             `bson:"h"`
	ContentData []byte              `bson:"contentData"`
	Lock        bool                `bson:"lock"`
	CreateTime  int64               `bson:"createTime"`
	UpdateTime  int64               `bson:"updateTime"`
}

func (item *DrawNodeInfoDbItem) ToDrawNodeInfo() (*board_draw_api.DrawNodeInfo, error) {
	content := &anypb.Any{}
	err := proto.Unmarshal(item.ContentData, content)
	if err != nil {
		content, err = anypb.New(&board_draw_type.UnkwownContent{})
		if err != nil {
			return nil, err
		}
	}
	return &board_draw_api.DrawNodeInfo{
		NodeId: item.NodeId,
		NodeStyle: &board_draw_api.NodeStyleInfo{
			BgColor:     item.NodeStyle.BgColor,
			BorderWidth: item.NodeStyle.BorderWidth,
			BorderColor: item.NodeStyle.BorderColor,
			FontColor:   item.NodeStyle.FontColor,
			Layer:       item.NodeStyle.Layer,
		},
		X:          item.X,
		Y:          item.Y,
		W:          item.W,
		H:          item.H,
		Content:    content,
		Lock:       item.Lock,
		CreateTime: item.CreateTime,
		UpdateTime: item.UpdateTime,
	}, nil
}

type _NodeInfoDao struct {
	mc *mongo.Collection
}

func newNodeInfoDao(db *mongo.Database) (*_NodeInfoDao, error) {
	mc := db.Collection(common.DB_NS_BOARD + "node")
	_, err := mc.Indexes().CreateOne(context.Background(), mongo.IndexModel{
		Keys: bson.D{{"drawId", 1}},
	})
	if err != nil {
		return nil, err
	}
	return &_NodeInfoDao{mc: mc}, nil
}

func (db *_NodeInfoDao) Insert(ctx context.Context, dbItem *DrawNodeInfoDbItem) error {
	_, err := db.mc.InsertOne(ctx, dbItem)
	return err
}

func (db *_NodeInfoDao) Exist(ctx context.Context, boardId, drawId, nodeId string) (bool, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId})
	return count > 0, err
}

func (db *_NodeInfoDao) Get(ctx context.Context, boardId, drawId, nodeId string) (*DrawNodeInfoDbItem, error) {
	retItem := &DrawNodeInfoDbItem{}
	err := db.mc.FindOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId}).Decode(retItem)
	return retItem, err
}

func (db *_NodeInfoDao) Remove(ctx context.Context, boardId, drawId, nodeId string) error {
	_, err := db.mc.DeleteOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId})
	return err
}

func (db *_NodeInfoDao) RemoveByDraw(ctx context.Context, boardId, drawId string) error {
	_, err := db.mc.DeleteMany(ctx, bson.M{"boardId": boardId, "drawId": drawId})
	return err
}

func (db *_NodeInfoDao) Count(ctx context.Context, boardId, drawId string) (uint32, error) {
	count, err := db.mc.CountDocuments(ctx, bson.M{"boardId": boardId, "drawId": drawId})
	return uint32(count), err
}

func (db *_NodeInfoDao) List(ctx context.Context, boardId, drawId string) ([]*DrawNodeInfoDbItem, error) {
	cursor, err := db.mc.Find(ctx, bson.M{"boardId": boardId, "drawId": drawId},
		options.Find().SetSort(bson.M{"createTime": 1}))
	if err != nil {
		return nil, err
	}
	retList := []*DrawNodeInfoDbItem{}
	err = cursor.All(ctx, &retList)
	return retList, err
}

func (db *_NodeInfoDao) UpdatePosition(ctx context.Context, boardId, drawId, nodeId string, x, y float32, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId},
		bson.M{"$set": bson.M{
			"x":          x,
			"y":          y,
			"updateTime": updateTime,
		}})
	return err
}

func (db *_NodeInfoDao) UpdateSize(ctx context.Context, boardId, drawId, nodeId string, w, h float32, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId},
		bson.M{"$set": bson.M{
			"w":          w,
			"h":          h,
			"updateTime": updateTime,
		}})
	return err
}

func (db *_NodeInfoDao) UpdateStyle(ctx context.Context, boardId, drawId, nodeId string, styleItem *NodeStyleInfoDbItem, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId},
		bson.M{"$set": bson.M{
			"nodeStyle":  styleItem,
			"updateTime": updateTime,
		}})
	return err
}

func (db *_NodeInfoDao) UpdateContent(ctx context.Context, boardId, drawId, nodeId string, contentData []byte, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId},
		bson.M{"$set": bson.M{
			"contentData": contentData,
			"updateTime":  updateTime,
		}})
	return err
}

func (db *_NodeInfoDao) UpdateLock(ctx context.Context, boardId, drawId, nodeId string, lock bool, updateTime int64) error {
	_, err := db.mc.UpdateOne(ctx, bson.M{"boardId": boardId, "drawId": drawId, "_id": nodeId},
		bson.M{"$set": bson.M{
			"lock":       lock,
			"updateTime": updateTime,
		}})
	return err
}
